home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / newsgroups / misc.20000824-20010305 / 000158_news@columbia.edu _Fri Dec 29 12:42:36 2000.msg < prev    next >
Internet Message Format  |  2020-01-01  |  4KB

  1. Return-Path: <news@columbia.edu>
  2. Received: from watsun.cc.columbia.edu (watsun.cc.columbia.edu [128.59.39.2])
  3.     by monire.cc.columbia.edu (8.9.3/8.9.3) with ESMTP id MAA12269
  4.     for <kermit.misc@cpunix.cc.columbia.edu>; Fri, 29 Dec 2000 12:42:36 -0500 (EST)
  5. Received: from newsmaster.cc.columbia.edu (newsmaster.cc.columbia.edu [128.59.59.30])
  6.     by watsun.cc.columbia.edu (8.8.5/8.8.5) with ESMTP id MAA19887
  7.     for <kermit.misc@watsun.cc.columbia.edu>; Fri, 29 Dec 2000 12:42:35 -0500 (EST)
  8. Received: (from news@localhost)
  9.     by newsmaster.cc.columbia.edu (8.9.3/8.9.3) id MAA06772
  10.     for kermit.misc@watsun.cc.columbia.edu; Fri, 29 Dec 2000 12:31:26 -0500 (EST)
  11. X-Authentication-Warning: newsmaster.cc.columbia.edu: news set sender to <news> using -f
  12. From: Russ Allbery <rra@stanford.edu>
  13. Subject: Re: Converting struct tm to time_t
  14. Date: 29 Dec 2000 09:23:59 -0800
  15. Organization: The Eyrie
  16. Message-ID: <ylito3uonk.fsf@windlord.stanford.edu>
  17. To: kermit.misc@columbia.edu
  18.  
  19. In comp.unix.programmer, Frank da Cruz <fdc@watsun.cc.columbia.edu> writes:
  20.  
  21. > If anybody has any helpful or simplifying suggestions, I'd be glad to
  22. > hear them.  The question is:
  23.  
  24. >   How to convert a struct tm (which already is expressed in GMT) to
  25. >   a time_t which expresses the clock time in GMT (not local time) in
  26. >   a way that is reliable (works in any timezone and takes daylight
  27. >   savings into account) and is portable to as many UNIX platforms as
  28. >   possible (and how to do the same things on the platforms to which
  29. >   this portability does not extend)?  The answer (as noted previously)
  30. >   is not mktime(), since it presumes its argument is in local time,
  31. >   not GMT.
  32.  
  33. > I'll copy this to comp.unix.programmer.
  34.  
  35. INN currently uses this, which seems to work fairly well.  I'm the author
  36. of this code; you can consider it to be in the public domain.  Note that
  37. this code requires that time_t be an arithmetic type, which may not work
  38. properly on some non-UNIX platforms (it could presumably be replaced by a
  39. long or something).
  40.  
  41. /* The number of days in each month. */
  42. static const int MONTHDAYS[] = {
  43.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  44. };
  45.  
  46. /* Whether a given year is a leap year. */
  47. #define ISLEAP(year) \
  48.     (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
  49.  
  50. /*
  51. **  Given a struct tm representing a calendar time in UTC, convert it to
  52. **  seconds since epoch.  Returns (time_t) -1 if the time is not
  53. **  convertable.  Note that this function does not canonicalize the provided
  54. **  struct tm, nor does it allow out of range values or years before 1970.
  55. */
  56. static time_t
  57. mktime_utc(const struct tm *tm)
  58. {
  59.     time_t result = 0;
  60.     int i;
  61.  
  62.     /* We do allow some ill-formed dates, but we don't do anything special
  63.        with them and our callers really shouldn't pass them to us.  Do
  64.        explicitly disallow the ones that would cause invalid array accesses
  65.        or other algorithm problems. */
  66.     if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
  67.         return (time_t) -1;
  68.  
  69.     /* Convert to a time_t. */
  70.     for (i = 1970; i < tm->tm_year + 1900; i++)
  71.         result += 365 + ISLEAP(i);
  72.     for (i = 0; i < tm->tm_mon; i++)
  73.         result += MONTHDAYS[i];
  74.     if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
  75.         result++;
  76.     result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
  77.     result = 60 * result + tm->tm_min;
  78.     result = 60 * result + tm->tm_sec;
  79.     return result;
  80. }
  81.  
  82. -- 
  83. Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>